package cn.dansj.common.utils.time;

import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;

public class CalendarUtils {
    public static final CalendarUtils INSTANCE = getInstance();

    public static CalendarUtils getInstance() {
        return new CalendarUtils(Calendar.getInstance());
    }

    static CalendarUtils getInstance(final Locale locale) {
        return new CalendarUtils(Calendar.getInstance(locale), locale);
    }

    public static LocalDateTime toLocalDateTime(final Calendar calendar) {
        return LocalDateTime.ofInstant(calendar.toInstant(), toZoneId(calendar));
    }

    public static OffsetDateTime toOffsetDateTime(final Calendar calendar) {
        return OffsetDateTime.ofInstant(calendar.toInstant(), toZoneId(calendar));
    }

    public static ZonedDateTime toZonedDateTime(final Calendar calendar) {
        return ZonedDateTime.ofInstant(calendar.toInstant(), toZoneId(calendar));
    }

    private static ZoneId toZoneId(final Calendar calendar) {
        return calendar.getTimeZone().toZoneId();
    }

    private final Calendar calendar;

    private final Locale locale;

    public CalendarUtils(final Calendar calendar) {
        this(calendar, Locale.getDefault());
    }

    CalendarUtils(final Calendar calendar, final Locale locale) {
        this.calendar = Objects.requireNonNull(calendar, "calendar");
        this.locale = Objects.requireNonNull(locale, "locale");
    }

    public int getDayOfMonth() {
        return calendar.get(Calendar.DAY_OF_MONTH);
    }

    public int getDayOfYear() {
        return calendar.get(Calendar.DAY_OF_YEAR);
    }

    public int getMonth() {
        return calendar.get(Calendar.MONTH);
    }

    String[] getMonthDisplayNames(final int style) {
        final Map<String, Integer> displayNames = calendar.getDisplayNames(Calendar.MONTH, style, locale);
        if (displayNames == null) {
            return null;
        }
        final String[] monthNames = new String[displayNames.size()];
        displayNames.forEach((k, v) -> monthNames[v] = k);
        return monthNames;
    }

    String[] getStandaloneLongMonthNames() {
        return getMonthDisplayNames(Calendar.LONG_STANDALONE);
    }

    String[] getStandaloneShortMonthNames() {
        return getMonthDisplayNames(Calendar.SHORT_STANDALONE);
    }

    public int getYear() {
        return calendar.get(Calendar.YEAR);
    }

    public LocalDateTime toLocalDateTime() {
        return toLocalDateTime(calendar);
    }

    public OffsetDateTime toOffsetDateTime() {
        return toOffsetDateTime(calendar);
    }

    public ZonedDateTime toZonedDateTime() {
        return toZonedDateTime(calendar);
    }
}
